using System.Collections.Generic;
using UnityEngine;

public class ChestSpawner : MonoBehaviour
{
    [System.Serializable]
    private struct RangeByLevel
    {
        public DungeonLevelSO dungeonLevel;
        [Range(0, 100)] public int min;
        [Range(0, 100)] public int max;
    }

    #region Header CHEST PREFAB

    [Space(10)]
    [Header("宝箱预制体")]

    #endregion Header CHEST PREFAB

    #region Tooltip

    [Tooltip("填充宝箱 预制件")]

    #endregion Tooltip

    [SerializeField] private GameObject chestPrefab;

    #region Header CHEST SPAWN CHANCE

    [Space(10)]
    [Header("宝箱生成几率")]

    #endregion Header CHEST SPAWN CHANCE

    #region Tooltip

    [Tooltip("生成宝箱的最小概率")]

    #endregion Tooltip

    [SerializeField]
    [Range(0, 100)]
    private int chestSpawnChanceMin;

    #region Tooltip

    [Tooltip("产生宝箱的最大概率")]

    #endregion Tooltip

    [SerializeField]
    [Range(0, 100)]
    private int chestSpawnChanceMax;

    #region Tooltip

    [Tooltip(" 您可以通过地牢等级覆盖宝箱生成几率")]

    #endregion Tooltip

    [SerializeField]
    private List<RangeByLevel> chestSpawnChanceByLevelList;

    #region Header CHEST SPAWN DETAILS

    [Space(10)]
    [Header("宝箱生成详情")]

    #endregion Header CHEST SPAWN DETAILS

    [SerializeField]
    private ChestSpawnEvent chestSpawnEvent;

    [SerializeField] private ChestSpawnPosition chestSpawnPosition;

    #region Tooltip

    [Tooltip("生成的最小物品数量（请注意，每种类型的弹药、健康和武器最多生成 1 个")]

    #endregion Tooltip

    [SerializeField]
    [Range(0, 3)]
    private int numberOfItemsToSpawnMin;

    #region Tooltip

    [Tooltip("生成的最大物品数量（请注意，每种类型的弹药、健康和武器最多生成 1 个")]

    #endregion Tooltip

    [SerializeField]
    [Range(0, 3)]
    private int numberOfItemsToSpawnMax;

    #region Header CHEST CONTENT DETAILS

    [Space(10)]
    [Header("箱内物品详情")]

    #endregion Header CHEST CONTENT DETAILS

    #region Tooltip

    [Tooltip("每个地牢级别要生成的武器及其生成比率")]

    #endregion Tooltip

    [SerializeField]
    private List<SpawnableObjectsByLevel<WeaponDetailsSO>> weaponSpawnByLevelList;

    #region Tooltip

    [Tooltip("每个级别生成的生命值范围")]

    #endregion Tooltip

    [SerializeField]
    private List<RangeByLevel> healthSpawnByLevelList;

    #region Tooltip

    [Tooltip("每个级别生成的弹药范围")]

    #endregion Tooltip

    [SerializeField]
    private List<RangeByLevel> ammoSpawnByLevelList;

    private bool chestSpawned = false;
    private Room chestRoom;

    private void OnEnable()
    {
        // 订阅房间更改事件
        StaticEventHandler.OnRoomChanged += StaticEventHandler_OnRoomChanged;

        // 订阅房间敌人击败事件
        StaticEventHandler.OnRoomEnemiesDefeated += StaticEventHandler_OnRoomEnemiesDefeated;
    }

    private void OnDisable()
    {
        // 取消订阅房间更改事件
        StaticEventHandler.OnRoomChanged -= StaticEventHandler_OnRoomChanged;

        // 取消订阅房间敌人击败活动
        StaticEventHandler.OnRoomEnemiesDefeated -= StaticEventHandler_OnRoomEnemiesDefeated;
    }

    /// <summary>
    /// 处理房间更改事件
    /// </summary>
    private void StaticEventHandler_OnRoomChanged(RoomChangedEventArgs roomChangedEventArgs)
    {
        // 如果我们还没有箱子所在的房间，请获取它
        if (chestRoom == null)
        {
            chestRoom = GetComponentInParent<InstantiatedRoom>().room;
        }

        // 如果宝箱是在进入房间时生成的，则生成宝箱
        if (!chestSpawned && chestSpawnEvent == ChestSpawnEvent.onRoomEntry && chestRoom == roomChangedEventArgs.room)
        {
            SpawnChest();
        }
    }

    /// <summary>
    /// 处理房间敌人击败事件
    /// </summary>
    private void StaticEventHandler_OnRoomEnemiesDefeated(RoomEnemiesDefeatedArgs roomEnemiesDefeatedArgs)
    {
        // 如果我们还没有箱子所在的房间，请获取它
        if (chestRoom == null)
        {
            chestRoom = GetComponentInParent<InstantiatedRoom>().room;
        }

        // 如果箱子是在敌人被击败时生成的，并且箱子在房间里，那么
        // 敌人已被击败
        if (!chestSpawned && chestSpawnEvent == ChestSpawnEvent.onEnemiesDefeated &&
            chestRoom == roomEnemiesDefeatedArgs.room)
        {
            SpawnChest();
        }
    }

    /// <summary>
    /// 生成箱子预制件
    /// </summary>
    private void SpawnChest()
    {
        chestSpawned = true;

        // 宝箱应该根据指定的几率生成吗？如果没有，请返回。
        if (!RandomSpawnChest()) return;

        // 获取要生成的弹药、健康和武器物品数量（每个最多 1 个）
        GetItemsToSpawn(out int ammoNum, out int healthNum, out int weaponNum);

        // 实例化宝箱
        GameObject chestGameObject = Instantiate(chestPrefab, this.transform);

        // 宝箱位置
        if (chestSpawnPosition == ChestSpawnPosition.atSpawnerPosition)
        {
            chestGameObject.transform.position = this.transform.position;
        }
        else if (chestSpawnPosition == ChestSpawnPosition.atPlayerPosition)
        {
            // 获取离玩家最近的生成位置
            Vector3 spawnPosition =
                HelperUtilities.GetSpawnPositionNearestToPlayer(GameManager.Instance.GetPlayer().transform.position);

            // 计算一些随机变化
            Vector3 variation = new Vector3(Random.Range(-0.5f, 0.5f), Random.Range(-0.5f, 0.5f), 0);

            chestGameObject.transform.position = spawnPosition + variation;
        }

        // 获取 Chest 组件
        Chest chest = chestGameObject.GetComponent<Chest>();

        // 初始化宝箱
        if (chestSpawnEvent == ChestSpawnEvent.onRoomEntry)
        {
            // 不要使用具体化效果
            chest.Initialize(false, GetHealthPercentToSpawn(healthNum), GetWeaponDetailsToSpawn(weaponNum),
                GetAmmoPercentToSpawn(ammoNum));
        }
        else
        {
            // 使用物化效果
            chest.Initialize(true, GetHealthPercentToSpawn(healthNum), GetWeaponDetailsToSpawn(weaponNum),
                GetAmmoPercentToSpawn(ammoNum));
        }
    }

    /// <summary>
    /// 根据宝箱生成几率检查是否应生成宝箱 - 如果宝箱应生成，则返回 true，否则为 false
    /// </summary>
    private bool RandomSpawnChest()
    {
        int chancePercent = Random.Range(chestSpawnChanceMin, chestSpawnChanceMax + 1);

        // 检查是否已为当前级别设置了覆盖机会百分比
        foreach (RangeByLevel rangeByLevel in chestSpawnChanceByLevelList)
        {
            if (rangeByLevel.dungeonLevel == GameManager.Instance.GetCurrentDungeonLevel())
            {
                chancePercent = Random.Range(rangeByLevel.min, rangeByLevel.max + 1);
                break;
            }
        }

        // 获取 1 到 100 之间的随机值
        int randomPercent = Random.Range(1, 100 + 1);

        if (randomPercent <= chancePercent)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    /// <summary>
    /// 获取要生成的物品数量 - 每个物品最多 1 个 - 总共最多 3 个
    /// </summary>
    private void GetItemsToSpawn(out int ammo, out int health, out int weapons)
    {
        ammo = 0;
        health = 0;
        weapons = 0;

        int numberOfItemsToSpawn = Random.Range(numberOfItemsToSpawnMin, numberOfItemsToSpawnMax + 1);

        int choice;

        if (numberOfItemsToSpawn == 1)
        {
            choice = Random.Range(0, 3);
            if (choice == 0)
            {
                weapons++;
                return;
            }

            if (choice == 1)
            {
                ammo++;
                return;
            }

            if (choice == 2)
            {
                health++;
                return;
            }

            return;
        }
        else if (numberOfItemsToSpawn == 2)
        {
            choice = Random.Range(0, 3);
            if (choice == 0)
            {
                weapons++;
                ammo++;
                return;
            }

            if (choice == 1)
            {
                ammo++;
                health++;
                return;
            }

            if (choice == 2)
            {
                health++;
                weapons++;
                return;
            }
        }
        else if (numberOfItemsToSpawn >= 3)
        {
            weapons++;
            ammo++;
            health++;
            return;
        }
    }

    /// <summary>
    /// 获取弹药百分比以生成
    /// </summary>
    private int GetAmmoPercentToSpawn(int ammoNumber)
    {
        if (ammoNumber == 0) return 0;

        // 获取关卡的弹药生成百分比范围
        foreach (RangeByLevel spawnPercentByLevel in ammoSpawnByLevelList)
        {
            if (spawnPercentByLevel.dungeonLevel == GameManager.Instance.GetCurrentDungeonLevel())
            {
                return Random.Range(spawnPercentByLevel.min, spawnPercentByLevel.max);
            }
        }

        return 0;
    }

    /// <summary>
    /// 获取生成的生命值百分比
    /// </summary>
    private int GetHealthPercentToSpawn(int healthNumber)
    {
        if (healthNumber == 0) return 0;

        // 获取关卡的弹药生成百分比范围
        foreach (RangeByLevel spawnPercentByLevel in healthSpawnByLevelList)
        {
            if (spawnPercentByLevel.dungeonLevel == GameManager.Instance.GetCurrentDungeonLevel())
            {
                return Random.Range(spawnPercentByLevel.min, spawnPercentByLevel.max);
            }
        }

        return 0;
    }

    /// <summary>
    /// 获取要生成的武器详细信息 - 如果没有要生成的武器或玩家已经拥有武器，则返回 null
    /// </summary>
    private WeaponDetailsSO GetWeaponDetailsToSpawn(int weaponNumber)
    {
        if (weaponNumber == 0) return null;

        // 创建用于根据指定项目的相对“比率”
        RandomSpawnableObject<WeaponDetailsSO> weaponRandom =
            new RandomSpawnableObject<WeaponDetailsSO>(weaponSpawnByLevelList);

        WeaponDetailsSO weaponDetails = weaponRandom.GetItem();

        return weaponDetails;
    }

    #region Validation

#if UNITY_EDITOR

    // 验证预制件细节 enetered
    private void OnValidate()
    {
        HelperUtilities.ValidateCheckNullValue(this, nameof(chestPrefab), chestPrefab);
        HelperUtilities.ValidateCheckPositiveRange(this, nameof(chestSpawnChanceMin), chestSpawnChanceMin,
            nameof(chestSpawnChanceMax), chestSpawnChanceMax, true);

        if (chestSpawnChanceByLevelList != null && chestSpawnChanceByLevelList.Count > 0)
        {
            HelperUtilities.ValidateCheckEnumerableValues(this, nameof(chestSpawnChanceByLevelList),
                chestSpawnChanceByLevelList);

            foreach (RangeByLevel rangeByLevel in chestSpawnChanceByLevelList)
            {
                HelperUtilities.ValidateCheckNullValue(this, nameof(rangeByLevel.dungeonLevel),
                    rangeByLevel.dungeonLevel);
                HelperUtilities.ValidateCheckPositiveRange(this, nameof(rangeByLevel.min), rangeByLevel.min,
                    nameof(rangeByLevel.max), rangeByLevel.max, true);
            }
        }

        HelperUtilities.ValidateCheckPositiveRange(this, nameof(numberOfItemsToSpawnMin), numberOfItemsToSpawnMin,
            nameof(numberOfItemsToSpawnMax), numberOfItemsToSpawnMax, true);

        if (weaponSpawnByLevelList != null && weaponSpawnByLevelList.Count > 0)
        {
            foreach (SpawnableObjectsByLevel<WeaponDetailsSO> weaponDetailsByLevel in weaponSpawnByLevelList)
            {
                HelperUtilities.ValidateCheckNullValue(this, nameof(weaponDetailsByLevel.dungeonLevel),
                    weaponDetailsByLevel.dungeonLevel);

                foreach (SpawnableObjectRatio<WeaponDetailsSO> weaponRatio in weaponDetailsByLevel
                             .spawnableObjectRatioList)
                {
                    HelperUtilities.ValidateCheckNullValue(this, nameof(weaponRatio.dungeonObject),
                        weaponRatio.dungeonObject);

                    HelperUtilities.ValidateCheckPositiveValue(this, nameof(weaponRatio.ratio), weaponRatio.ratio,
                        true);
                }
            }
        }

        if (healthSpawnByLevelList != null && healthSpawnByLevelList.Count > 0)
        {
            HelperUtilities.ValidateCheckEnumerableValues(this, nameof(healthSpawnByLevelList), healthSpawnByLevelList);

            foreach (RangeByLevel rangeByLevel in healthSpawnByLevelList)
            {
                HelperUtilities.ValidateCheckNullValue(this, nameof(rangeByLevel.dungeonLevel),
                    rangeByLevel.dungeonLevel);
                HelperUtilities.ValidateCheckPositiveRange(this, nameof(rangeByLevel.min), rangeByLevel.min,
                    nameof(rangeByLevel.max), rangeByLevel.max, true);
            }
        }

        if (ammoSpawnByLevelList != null && ammoSpawnByLevelList.Count > 0)
        {
            HelperUtilities.ValidateCheckEnumerableValues(this, nameof(ammoSpawnByLevelList), ammoSpawnByLevelList);
            foreach (RangeByLevel rangeByLevel in ammoSpawnByLevelList)
            {
                HelperUtilities.ValidateCheckNullValue(this, nameof(rangeByLevel.dungeonLevel),
                    rangeByLevel.dungeonLevel);
                HelperUtilities.ValidateCheckPositiveRange(this, nameof(rangeByLevel.min), rangeByLevel.min,
                    nameof(rangeByLevel.max), rangeByLevel.max, true);
            }
        }
    }

#endif

    #endregion Validation
}